package qc.module.qms.api.job;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import qc.common.core.enums.DataManagementTypeEnum;
import qc.common.core.exception.QCPromptException;
import qc.common.core.json.JsonParserUtil;
import qc.common.core.utils.DateUtil;
import qc.common.core.utils.TimeSpanUtil;
import qc.module.platform.dto.dbTable.DBTableFullDto;
import qc.module.qms.api.RestTemplatePlatform;
import qc.module.qms.dto.exchange.category.ExchangeCategoryDto;
import qc.module.qms.dto.exchange.log.DataExchangeLogDto;
import qc.module.qms.dto.station.StationDto;
import qc.module.qms.service.QmsStationService;
import qc.module.qms.service.exchange.ExchangeCategoryService;
import qc.module.qms.service.exchange.ExchangeDataService;
import qc.module.qms.service.exchange.ExchangeLogService;
import qc.module.qms.service.ynsyjpt.YnsyjptPptnDataGenerator;
import qc.module.qms.service.ynsyjpt.YnsyjptRsvrDataGenerator;
import tech.powerjob.worker.core.processor.ProcessResult;
import tech.powerjob.worker.core.processor.TaskContext;
import tech.powerjob.worker.core.processor.sdk.BasicProcessor;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

/**
 * 生成省汇集平台上传数据任务处理器
 *
 * @author QuCheng Tech
 * @since 2024/1/29
 */
@Component
public class GenerateYnhjptDataProcessor implements BasicProcessor {
    @Autowired
    private ExchangeCategoryService categoryService;

    @Autowired
    private QmsStationService stationService;

    @Autowired
    private ExchangeDataService exchangeDataService;

    @Autowired
    private ExchangeLogService exchangeLogService;

    //不同数据分类的数据生成器
    @Autowired
    private YnsyjptRsvrDataGenerator ynsyjptRsvrDataGenerator;

    @Autowired
    private YnsyjptPptnDataGenerator ynsyjptPptnDataGenerator;

    /**
     * 静态定义--云南省汇集平台上传数据分类ID集合
     */
    public final int[] ynhjptCategoryIds = new int[]{0x1, 0x2};

    /**
     * 静态定义--生成上传数据延迟的秒速，由于原始数据接收会有延迟，因此需要进行延迟生成上传数据
     */
    public final int generateDataDelaySeconds = 30;

    @Autowired
    private RestTemplatePlatform restTemplatePlatform;

    @Override
    public ProcessResult process(TaskContext taskContext) throws Exception {
        //生成上传省汇集平台数据
        //水位、雨量数据分开处理
        //1.从上传水位数据表中获取最新1条数据，根据最新数据时间+上传数据间隔频率要求计算本次是否需要生成上传数据
        //2.水位数据处理：从原始数据表中查询水位数据；数据值处理：原始水位数据+高程；频率处理：不存在对应时间点采用线性插值或最近1条
        //3.雨量数据处理：从原始数据表中查询水位数据；数据值处理：（默认为0）时间点上的累计雨量-前DR分钟时间的累计雨量（2个时间点的总累计雨量其中1个没有时值为0）

        Date now = DateUtil.getNowDate();
        //测试用--对处理数据的截止时间进行赋值
        //now = DateUtil.parseDate("2024-3-31 22:00:00");
        //遍历交换数据分类--获取每个分类下交换的站点；遍历交换数据站点，逐个站点进行数据查询和处理
        if (ynhjptCategoryIds != null && ynhjptCategoryIds.length > 0x0) {
            for (int categoryId : ynhjptCategoryIds) {
                //获取分类中的站点集合
                List<StationDto> categoryStations = stationService.getByCategoryId(categoryId);
                for (StationDto station : categoryStations) {
                    System.out.println("省汇集平台定时生成数据处理，categoryId="+categoryId +"，生成["+(categoryId==0x1?"水位库容":"降雨量")+"]数据"+"，根据数据分类得到的站点信息，stcd=" + station.getStcd() + " getParams=" + station.getParams());
                }
                if (categoryStations != null && categoryStations.size() > 0x0) {
                    //数据分类中有交换站点，判断是否需要处理
                    //获取交换数据分类信息，需要使用其中设置的交换频率等参数
                    ExchangeCategoryDto category = categoryService.get(categoryId);
                    System.out.println("省汇集平台定时生成数据处理，获取数据分类信息，category=" + category.getTablecode() + " getParams=" + category.getParams());
                    if (category != null && StringUtils.isNotBlank(category.getTablecode())) {
                        //根据数据库表编码获取完整信息，再从信息中获取sql语句、查询数据库连接信息和列信息
                        DBTableFullDto tableFullInfo = restTemplatePlatform.getDbTableFullInfo(category.getTablecode());
                        //数据库连接信息
                        String dbUrl = "";
                        String dbUser = "";
                        String dbPassword = "";
                        if (tableFullInfo != null) {
                            if (tableFullInfo.getDb() != null) {
                                //解析数据库连接信息
                                String dbConJsonString = tableFullInfo.getDb().getCon();
                                if (StringUtils.isNotBlank(dbConJsonString)) {
                                    //Json对象进行获取
                                    dbUrl = JsonParserUtil.getString(dbConJsonString, "url");
                                    dbUser = JsonParserUtil.getString(dbConJsonString, "user");
                                    dbPassword = JsonParserUtil.getString(dbConJsonString, "password");
                                }
                            }
                        }
                        for (StationDto station : categoryStations) {
                            //此处的stcd为交换数据表中的目标stcd，查询原始数据需要从站点参数中获取
                            String stcd = station.getStcd();
                            //原始数据对应的stcd，默认与目标stcd相同，从站点参数中获取
                            String sourceStcd = stcd;
                            //水库注册号
                            String rscd = null;
                            //根据数据分类获取参数--解析参数中的间隔频率分钟数
                            int dataIntervalMinutes = 0x5;
                            //补传最大天数
                            int maxDays = 0x3;

                            System.out.println("省汇集平台定时生成数据处理，获取站点参数中的原始数据站号，stcd=" + stcd + " getParams=" + station.getParams());
                            //水位、雨量的频率应该从数据分类参数中获取；同一类数据应该是同一种频率要求；先从数据分类参数中获取，如果站点参数中也设置了使用站点参数中的配置；
                            //补传最大天数应该从站点参数中获取，可以每个站点配置不同；
                            if (station != null && StringUtils.isNotBlank(station.getParams())) {
                                //固定按交换数据分类id区分是水位库容还是降雨量数据
                                if (categoryId == 0x2)
                                    dataIntervalMinutes = JsonParserUtil.getIntValue(station.getParams(), "run>上报雨量频率分钟", 0x5);
                                else
                                    dataIntervalMinutes = JsonParserUtil.getIntValue(station.getParams(), "run>上报水位频率分钟", 0x5);
                                maxDays = JsonParserUtil.getIntValue(station.getParams(), "run>补传最大天数", 0x3);
                            }

                            //查询交换数据表中的最新数据，用于判断本次是否需要处理和写入数据
                            //// TODO: 2024/1/30 后继可以使用根据分类和站点编码自动生成sql进行查询，通过配置的数据库表列信息自动生成sql 
                            //目前固定为：select tm from tableCode where stcd='' and tm<now() order by tm desc limit 1;
                            Date latestDataTime = exchangeDataService.getLatestDataTime(dbUrl, dbUser, dbPassword, category.getTablecode(), "tm", "stcd", stcd, now);
                            //计算本次生成数据的起始时间，如果不需要生成起始时间为null
                            Date beginTime = null;
                            //根据当前时间计算本次生成数据的截止时间，最终要判断生成数据的截止时间不能小于起始时间（可以相同表示要生成一个时间点的数据）
                            //处理生成数据需要延迟，如果当前时间小于设定的延迟时间，将生成数据的截止时间往前1个时段；在计算截止时间时先将传入的当前时间减去延迟秒数
                            Date plusDelaySecondsTime = DateUtil.addSeconds(now, -generateDataDelaySeconds);
                            Date endTime = TimeSpanUtil.getBeginTime(plusDelaySecondsTime, 60);
                            int nowDateMonth = DateUtil.getMonth(plusDelaySecondsTime);
                            if (nowDateMonth >= 5 && nowDateMonth <= 10)
                                endTime = TimeSpanUtil.getBeginTime(plusDelaySecondsTime, 5);

                            //如果Date为null表示没有任何数据，默认处理N天前的数据
                            if (latestDataTime == null) {
                                //N天前的时间是从当日0点往前N天；小时为0点；不需要判断间隔分钟数
                                beginTime = DateUtil.addDays(DateUtil.getTodayDate(), -maxDays);
                            } else {
                                //交换数据表中已有数据，根据最新数据时间处理；判断最新数据时间所在月份得到间隔分钟数，要处理数据的开始时间=最新数据时间+间隔分钟数
                                int latestDataMonth = DateUtil.getMonth(latestDataTime);
                                //2024-5-8，修改为固定根据处理数据的时间点进行判断；根据月份判断即可，月份在5-10月按5分钟，其他月份按60分钟；
                                if (latestDataMonth > 10 || latestDataMonth < 5)
                                    beginTime = DateUtil.addMinutes(latestDataTime, 60);
                                else
                                    beginTime = DateUtil.addMinutes(latestDataTime, 5);
                            }
                            //判断如果本次生成数据起始时间为空则不需要生成数据；如果起始时间不为空，并且≤截止时间则需要生成数据；
                            if (beginTime != null && endTime.before(beginTime) == false) {
                                //初始化生成数据执行结果
                                boolean taskExecuteSuccess = false;
                                String taskExecuteInfo = null;

                                //需要获取原始数据库表和数据库连接信息
                                //原始数据表，需要固定指定表名，或者在数据分类参数配置中指定
                                //2024-9-29，原始数据表由DeviceTimingDataRecord修改为MS_QZJ_SRCDATA；计讯接收软件接收到数据后写入DeviceTimingDataRecord，由触发器触发到MS_QZJ_SRCDATA
                                //原始数据使用MS_QZJ_SRCDATA表可以从其他接收数据库中直接将数据导入以进行数据处理；如南康河中云服务器接收数据中断，从南康河电站接收的前置机数据库中导入缺失时间段内的数据；
                                //String defaultSrcDbTableCode="DeviceTimingDataRecord";
                                String defaultSrcDbTableCode = "MS_QZJ_SRCDATA";
                                String sourceDbTableCode = null;
                                if (category != null && StringUtils.isNotBlank(category.getParams())) {
                                    sourceDbTableCode = JsonParserUtil.getString(category.getParams(), "原始数据来源表");
                                }
                                if (StringUtils.isBlank(sourceDbTableCode))
                                    sourceDbTableCode = defaultSrcDbTableCode;
                                //根据数据库表编码获取完整信息，再从信息中获取sql语句、查询数据库连接信息和列信息
                                DBTableFullDto srcTableFullInfo = restTemplatePlatform.getDbTableFullInfo(sourceDbTableCode);

                                if (categoryId == 0x1) {
                                    //生成水位库容数据，调用数据生成器中的方法
                                    try {
                                        taskExecuteInfo = ynsyjptRsvrDataGenerator.generate(station, beginTime, endTime, tableFullInfo, srcTableFullInfo);

                                        //执行完成的都设置为执行成功
                                        taskExecuteSuccess = true;
                                    } catch (QCPromptException ex) {
                                        taskExecuteInfo = ex.getMessage();
                                    } catch (SQLException ex) {
                                        taskExecuteInfo = ex.getMessage();
                                    }
                                } else if (categoryId == 0x2) {
                                    //生成雨量数据，调用数据生成器中的方法
                                    try {
                                        taskExecuteInfo = ynsyjptPptnDataGenerator.generate(station, beginTime, endTime, tableFullInfo, srcTableFullInfo);

                                        //执行完成的都设置为执行成功
                                        taskExecuteSuccess = true;
                                    } catch (QCPromptException ex) {
                                        taskExecuteInfo = ex.getMessage();
                                    } catch (SQLException ex) {
                                        taskExecuteInfo = ex.getMessage();
                                    }
                                }

                                //新增日志记录
                                DataExchangeLogDto log = new DataExchangeLogDto();
                                log.setIsmanual(false);
                                log.setOptype(DataManagementTypeEnum.INSERT.getIndex());
                                log.setCid(categoryId);
                                log.setStcd(stcd);
                                log.setBegintm(DateUtil.getDateTimeString(beginTime));
                                log.setEndtm(DateUtil.getDateTimeString(endTime));
                                if (taskExecuteSuccess)
                                    log.setExecresult(0b11);
                                else
                                    log.setExecresult(0b01);
                                log.setExectm(DateUtil.getDateTimeString(now));
                                log.setExecinfo(taskExecuteInfo);

                                String addLogResult = exchangeLogService.addLog(log);
                                if (StringUtils.isBlank(addLogResult))
                                    System.out.println("省汇集平台定时生成数据处理，处理站点编码=" + stcd + "，站点名称=" + station.getStnm() + "，时间段=" + DateUtil.getDateTimeString(beginTime) + "~~" + DateUtil.getDateTimeString(endTime));

                            }
                        }
                    }
                }
            }
        }

        return new ProcessResult(true,"生成省汇集平台上传数据成功");
    }
}
